package plugin

import (
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/stretchr/testify/assert"
)

func TestStandardMethodEncodeMethodCall(t *testing.T) {
	scenarios := []struct {
		value MethodCall
		data  []byte
	}{
		{
			value: MethodCall{
				Method:    "12345678",
				Arguments: "foobar",
			},
			data: []byte{
				0x07, 0x08, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, // string type, string length, "123456"
				0x37, 0x38, 0x07, 0x06, 0x66, 0x6f, 0x6f, 0x62, // "78", string type, string length, "foob"
				0x61, 0x72, // "ar"
			},
		},
		{
			value: MethodCall{
				Method:    "",
				Arguments: float64(3.1415),
			},
			data: []byte{
				0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, // string type, string length, "", float type, 5 alignment bytes
				0x6f, 0x12, 0x83, 0xc0, 0xca, 0x21, 0x09, 0x40, // encoded float value (3.1415)
			},
		},
		{
			value: MethodCall{
				Method:    "1",
				Arguments: float64(3.1415),
			},
			data: []byte{
				0x07, 0x01, 0x31, 0x06, 0x00, 0x00, 0x00, 0x00, // string type, string length, "1", float type, 4 alignment bytes
				0x6f, 0x12, 0x83, 0xc0, 0xca, 0x21, 0x09, 0x40, // encoded float value (3.1415)
			},
		},
		{
			value: MethodCall{
				Method:    "12",
				Arguments: float64(3.1415),
			},
			data: []byte{
				0x07, 0x02, 0x31, 0x32, 0x06, 0x00, 0x00, 0x00, // string type, string length, "12", float type, 3 alignment bytes
				0x6f, 0x12, 0x83, 0xc0, 0xca, 0x21, 0x09, 0x40, // encoded float value (3.1415)
			},
		},
		{
			value: MethodCall{
				Method:    "123",
				Arguments: float64(3.1415),
			},
			data: []byte{
				0x07, 0x03, 0x31, 0x32, 0x33, 0x06, 0x00, 0x00, // string type, string length, "123", float type, 2 alignment bytes
				0x6f, 0x12, 0x83, 0xc0, 0xca, 0x21, 0x09, 0x40, // encoded float value (3.1415)
			},
		},
		{
			value: MethodCall{
				Method:    "1234",
				Arguments: float64(3.1415),
			},
			data: []byte{
				0x07, 0x04, 0x31, 0x32, 0x33, 0x34, 0x06, 0x00, // string type, string length, "1234", float type, 1 alignment byte
				0x6f, 0x12, 0x83, 0xc0, 0xca, 0x21, 0x09, 0x40, // encoded float value (3.1415)
			},
		},
		{
			value: MethodCall{
				Method:    "12345",
				Arguments: float64(3.1415),
			},
			data: []byte{
				0x07, 0x05, 0x31, 0x32, 0x33, 0x34, 0x35, 0x06, // string type, string length, "12345", float type
				0x6f, 0x12, 0x83, 0xc0, 0xca, 0x21, 0x09, 0x40, // encoded float value (3.1415)
			},
		},
		{
			value: MethodCall{
				Method:    "123456",
				Arguments: float64(3.1415),
			},
			data: []byte{
				0x07, 0x06, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, // string type, string length, "123456"
				0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // float type, alignment bytes
				0x6f, 0x12, 0x83, 0xc0, 0xca, 0x21, 0x09, 0x40, // encoded float value (3.1415)
			},
		},
	}
	codec := StandardMethodCodec{}

	for _, s := range scenarios {
		t.Logf("encoding: %v\n", s.value)

		encodedData, err := codec.EncodeMethodCall(s.value)
		if err != nil {
			t.Fatal(err)
		}
		t.Logf(spew.Sdump(encodedData))
		assert.Equal(t, s.data, encodedData)

		decodedValue, err := codec.DecodeMethodCall(encodedData)
		if err != nil {
			t.Fatal(err)
		}

		assert.Equal(t, s.value, decodedValue)
	}
}

// TestStandardMethodDecodeRealWorldMethodCall tests decoding a method call
// found in the real world, that posed some problems for an early
// implementation.
func TestStandardMethodDecodeRealWorldMethodCall(t *testing.T) {
	scenarios := []struct {
		value MethodCall
		data  []byte
	}{
		{
			value: MethodCall{
				Method: "play",
				Arguments: map[interface{}]interface{}{
					"playerId":       "fcc45fbf-d44f-4468-8d9a-f9cf64e3443f",
					"mode":           "PlayerMode.MEDIA_PLAYER",
					"url":            "https://luan.xyz/files/audio/ambient_c_motion.mp3",
					"isLocal":        false,
					"volume":         float64(1),
					"position":       nil,
					"respectSilence": false,
				},
			},
			data: []byte{0x07, 0x04, 0x70, 0x6c, 0x61, 0x79, 0x0d, 0x07, 0x07, 0x03, 0x75, 0x72, 0x6c, 0x07, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x6c, 0x75, 0x61, 0x6e, 0x2e, 0x78, 0x79, 0x7a, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2f, 0x61, 0x6d, 0x62, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x5f, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6d, 0x70, 0x33, 0x07, 0x07, 0x69, 0x73, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x02, 0x07, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x07, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x07, 0x0e, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x53, 0x69, 0x6c, 0x65, 0x6e, 0x63, 0x65, 0x02, 0x07, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x07, 0x24, 0x66, 0x63, 0x63, 0x34, 0x35, 0x66, 0x62, 0x66, 0x2d, 0x64, 0x34, 0x34, 0x66, 0x2d, 0x34, 0x34, 0x36, 0x38, 0x2d, 0x38, 0x64, 0x39, 0x61, 0x2d, 0x66, 0x39, 0x63, 0x66, 0x36, 0x34, 0x65, 0x33, 0x34, 0x34, 0x33, 0x66, 0x07, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x07, 0x17, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x2e, 0x4d, 0x45, 0x44, 0x49, 0x41, 0x5f, 0x50, 0x4c, 0x41, 0x59, 0x45, 0x52},
		},
	}

	codec := StandardMethodCodec{}

	for _, s := range scenarios {
		result, err := codec.DecodeMethodCall(s.data)
		if err != nil {
			t.Fatal(err)
		}
		assert.Equal(t, s.value, result)
	}
}
